<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Tutorial 27: Post Processing</title>
<html xmlns="http://www.w3.org/1999/xhtml">
<!-- Wanted to avoid copying .css to each folder, so copied default .css from doxyen in here, kicked out most stuff we don't need for examples and modified some a little bit. 
     Target was having a single html in each example folder which is created from the main.cpp files and needs no files besides some images below media folder.
     Feel free to improve :)
	 -->
<style>
body, table, div, p, dl {
	font: 400 14px/22px;
}
body {
	background-color: #F0F0F0;
	color: black;
	margin-left: 5%;
	margin-right: 5%;
}
p.reference, p.definition {
	font: 400 14px/22px;
}
.title {
	font: 400 14px/28px;
	font-size: 150%;
	font-weight: bold;
	margin: 10px 2px;
}
h1, h2, h3, h4, h5, h6 {
	-webkit-transition: text-shadow 0.5s linear;
	-moz-transition: text-shadow 0.5s linear;
	-ms-transition: text-shadow 0.5s linear;
	-o-transition: text-shadow 0.5s linear;
	transition: text-shadow 0.5s linear;
	margin-right: 15px;
}
caption {
	font-weight: bold;
}
h3.version {
	font-size: 90%;
	text-align: center;
}
a {
	color: #3D578C;
	font-weight: normal;
	text-decoration: none;
}
.contents a:visited {
	color: #4665A2;
}
a:hover {
	text-decoration: underline;
}
a.el {
	font-weight: bold;
}
a.code, a.code:visited, a.line, a.line:visited {
	color: #4665A2; 
}
a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
	color: #4665A2; 
}
pre.fragment {
	border: 1px solid #C4CFE5;
	background-color: #FBFCFD;
	padding: 4px 6px;
	margin: 4px 8px 4px 2px;
	overflow: auto;
	word-wrap: break-word;
	font-size:  9pt;
	line-height: 125%;
	font-family: monospace, fixed;
	font-size: 105%;
}
div.fragment {
	padding: 0px;
	margin: 4px 8px 4px 2px;
	background-color: #FBFCFD;
	border: 1px solid #C4CFE5;
}
div.line {
	font-family: monospace, fixed;
	font-size: 13px;
	min-height: 13px;
	line-height: 1.0;
	text-wrap: unrestricted;
	white-space: -moz-pre-wrap; /* Moz */
	white-space: -pre-wrap;     /* Opera 4-6 */
	white-space: -o-pre-wrap;   /* Opera 7 */
	white-space: pre-wrap;      /* CSS3  */
	word-wrap: break-word;      /* IE 5.5+ */
	text-indent: -53px;
	padding-left: 53px;
	padding-bottom: 0px;
	margin: 0px;
	-webkit-transition-property: background-color, box-shadow;
	-webkit-transition-duration: 0.5s;
	-moz-transition-property: background-color, box-shadow;
	-moz-transition-duration: 0.5s;
	-ms-transition-property: background-color, box-shadow;
	-ms-transition-duration: 0.5s;
	-o-transition-property: background-color, box-shadow;
	-o-transition-duration: 0.5s;
	transition-property: background-color, box-shadow;
	transition-duration: 0.5s;
}
div.contents {
	margin-top: 10px;
	margin-left: 12px;
	margin-right: 8px;
}
div.center {
	text-align: center;
	margin-top: 0px;
	margin-bottom: 0px;
	padding: 0px;
}
div.center img {
	border: 0px;
}
span.keyword {
	color: #008000
}
span.keywordtype {
	color: #604020
}
span.keywordflow {
	color: #e08000
}
span.comment {
	color: #800000
}
span.preprocessor {
	color: #806020
}
span.stringliteral {
	color: #002080
}
span.charliteral {
	color: #008080
}
blockquote {
	background-color: #F7F8FB;
	border-left: 2px solid #9CAFD4;
	margin: 0 24px 0 4px;
	padding: 0 12px 0 16px;
}
hr {
	height: 0px;
	border: none;
	border-top: 1px solid #4A6AAA;
}
address {
	font-style: normal;
	color: #2A3D61;
}
div.header {
	background-image:url('nav_h.png');
	background-repeat:repeat-x;
	background-color: #F9FAFC;
	margin:  0px;
	border-bottom: 1px solid #C4CFE5;
}
div.headertitle {
	padding: 5px 5px 5px 10px;
}
.image {
	text-align: center;
}
.caption {
	font-weight: bold;
}
div.zoom {
	border: 1px solid #90A5CE;
}
tr.heading h2 {
	margin-top: 12px;
	margin-bottom: 4px;
}
</style>
</head>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--END TITLEAREA-->
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Tutorial 27: Post Processing </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><div class="image">
<img src="../../media/example_screenshots/027shot.jpg" alt="027shot.jpg"/>
</div>
 <p>This tutorial shows how to implement post processing for D3D9 and OpenGL with the engine. In order to do post processing, scene objects are firstly rendered to render target. With the help of screen quad, the render target texture is then drawn on the quad with shader-defined effects applied.</p>
<p>This tutorial shows how to create a screen quad. It also shows how to create a render target texture and associate it with the quad. Effects are defined as shaders which are applied during rendering the quad with the render target texture attached to it.</p>
<p>A simple color inverse example is presented in this tutorial. The effect is written in HLSL and GLSL.</p>
<dl class="section author"><dt>Author</dt><dd>Boshen Guan</dd></dl>
<p>We include all headers and define necessary variables as we have done before. </p><div class="fragment"><div class="line"><span class="preprocessor">#include &quot;driverChoice.h&quot;</span></div><div class="line"><span class="preprocessor">#include &quot;exampleHelper.h&quot;</span></div><div class="line"></div><div class="line"><span class="preprocessor">#include &lt;irrlicht.h&gt;</span></div><div class="line"></div><div class="line"><span class="keyword">using namespace </span>irr;</div><div class="line"></div><div class="line"><span class="preprocessor">#ifdef _MSC_VER</span></div><div class="line"><span class="preprocessor">#pragma comment(lib, &quot;Irrlicht.lib&quot;)</span></div><div class="line"><span class="preprocessor">#endif</span></div></div><!-- fragment --><p> We write a class derived from IShaderConstantSetCallBack class and implement OnSetConstants callback interface. In this callback, we will set constants used by the shader. In this example, our HLSL shader needs texture size as input in its vertex shader. Therefore, we set texture size in OnSetConstants callback using setVertexShaderConstant function. </p><div class="fragment"><div class="line">IrrlichtDevice* device = 0;</div><div class="line">video::ITexture* rt = 0;</div><div class="line"></div><div class="line"><span class="keyword">class </span>QuadShaderCallBack : <span class="keyword">public</span> video::IShaderConstantSetCallBack</div><div class="line">{</div><div class="line"><span class="keyword">public</span>:</div><div class="line">    QuadShaderCallBack() : FirstUpdate(true), TextureSizeID(-1), TextureSamplerID(-1)</div><div class="line">    { }</div><div class="line"></div><div class="line">    <span class="keyword">virtual</span> <span class="keywordtype">void</span> OnSetConstants(video::IMaterialRendererServices* services,</div><div class="line">            s32 userData)</div><div class="line">    {</div><div class="line">        core::dimension2d&lt;u32&gt; size = rt-&gt;getSize();</div><div class="line"></div><div class="line">        <span class="comment">// get texture size array</span></div><div class="line">        f32 textureSize[] = </div><div class="line">        {</div><div class="line">            (f32)size.Width, (f32)size.Height</div><div class="line">        };</div><div class="line"></div><div class="line">        <span class="keywordflow">if</span> ( FirstUpdate )</div><div class="line">        {</div><div class="line">            TextureSizeID = services-&gt;getVertexShaderConstantID(<span class="stringliteral">&quot;TextureSize&quot;</span>);</div><div class="line">            TextureSamplerID = services-&gt;getPixelShaderConstantID(<span class="stringliteral">&quot;TextureSampler&quot;</span>);</div><div class="line">        }</div><div class="line"></div><div class="line">        <span class="comment">// set texture size to vertex shader</span></div><div class="line">        services-&gt;setVertexShaderConstant(TextureSizeID, reinterpret_cast&lt;f32*&gt;(textureSize), 2);</div><div class="line">        </div><div class="line">        <span class="comment">// set texture for an OpenGL driver</span></div><div class="line">        s32 textureLayer = 0;</div><div class="line">        services-&gt;setPixelShaderConstant(TextureSamplerID, &amp;textureLayer, 1);</div><div class="line">    }</div><div class="line"></div><div class="line"><span class="keyword">private</span>:</div><div class="line">    <span class="keywordtype">bool</span> FirstUpdate;</div><div class="line">    s32 TextureSizeID;</div><div class="line">    s32 TextureSamplerID;</div><div class="line">};</div><div class="line"></div><div class="line"><span class="keyword">class </span>ScreenQuad : <span class="keyword">public</span> IReferenceCounted</div><div class="line">{</div><div class="line"><span class="keyword">public</span>:</div><div class="line"></div><div class="line">    ScreenQuad(video::IVideoDriver* driver)</div><div class="line">        : Driver(driver)</div><div class="line">    {</div><div class="line">        <span class="comment">// --------------------------------&gt; u</span></div><div class="line">        <span class="comment">// |[1](-1, 1)----------[2](1, 1)</span></div><div class="line">        <span class="comment">// | | ( 0, 0)         / | (1, 0)</span></div><div class="line">        <span class="comment">// | |               /   |</span></div><div class="line">        <span class="comment">// | |             /     |</span></div><div class="line">        <span class="comment">// | |           /       |</span></div><div class="line">        <span class="comment">// | |         /         |</span></div><div class="line">        <span class="comment">// | |       /           |</span></div><div class="line">        <span class="comment">// | |     /             |</span></div><div class="line">        <span class="comment">// | |   /               |</span></div><div class="line">        <span class="comment">// | | /                 |</span></div><div class="line">        <span class="comment">// |[0](-1, -1)---------[3](1, -1)</span></div><div class="line">        <span class="comment">// |   ( 0,  1)            (1,  1)</span></div><div class="line">        <span class="comment">// V </span></div><div class="line">        <span class="comment">// v</span></div></div><!-- fragment --><p> A screen quad is composed of two adjacent triangles with 4 vertices. Vertex [0], [1] and [2] create the first triangle and Vertex [0], [2] and [3] create the second one. To map texture on the quad, UV coordinates are assigned to the vertices. The origin of UV coordinate locates on the top-left corner. And the value of UVs range from 0 to 1. </p><div class="fragment"><div class="line">        <span class="comment">// define vertices array</span></div><div class="line"></div><div class="line">        Vertices[0] = irr::video::S3DVertex(-1.0f, -1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 0.0f, 1.0f);</div><div class="line">        Vertices[1] = irr::video::S3DVertex(-1.0f,  1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 0.0f, 0.0f);</div><div class="line">        Vertices[2] = irr::video::S3DVertex( 1.0f,  1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 1.0f, 0.0f);</div><div class="line">        Vertices[3] = irr::video::S3DVertex( 1.0f, -1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 1.0f, 1.0f);</div><div class="line"></div><div class="line">        <span class="comment">// define indices for triangles</span></div><div class="line"></div><div class="line">        Indices[0] = 0;</div><div class="line">        Indices[1] = 1;</div><div class="line">        Indices[2] = 2;</div><div class="line">        Indices[3] = 0;</div><div class="line">        Indices[4] = 2;</div><div class="line">        Indices[5] = 3;</div><div class="line"></div><div class="line">        <span class="comment">// turn off lighting as default</span></div><div class="line">        Material.setFlag(video::EMF_LIGHTING, <span class="keyword">false</span>);</div><div class="line"></div><div class="line">        <span class="comment">// set texture warp settings to clamp to edge pixel</span></div><div class="line">        <span class="keywordflow">for</span> (u32 i = 0; i &lt; video::MATERIAL_MAX_TEXTURES; i++)</div><div class="line">        {</div><div class="line">            Material.TextureLayer[i].TextureWrapU = video::ETC_CLAMP_TO_EDGE;</div><div class="line">            Material.TextureLayer[i].TextureWrapV = video::ETC_CLAMP_TO_EDGE;</div><div class="line">        }</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="keyword">virtual</span> ~ScreenQuad() {}</div><div class="line"></div><div class="line"></div><div class="line">    <span class="keyword">virtual</span> <span class="keywordtype">void</span> render()</div><div class="line">    {</div><div class="line">        <span class="comment">// set the material of screen quad</span></div><div class="line">        Driver-&gt;setMaterial(Material);</div><div class="line"></div><div class="line">        <span class="comment">// set matrices to fit the quad to full viewport</span></div><div class="line">        Driver-&gt;setTransform(video::ETS_WORLD, core::IdentityMatrix);</div><div class="line">        Driver-&gt;setTransform(video::ETS_VIEW, core::IdentityMatrix);</div><div class="line">        Driver-&gt;setTransform(video::ETS_PROJECTION, core::IdentityMatrix);</div><div class="line"></div><div class="line">        <span class="comment">// draw screen quad </span></div><div class="line">        Driver-&gt;drawVertexPrimitiveList(Vertices, 4, Indices, 2);</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="keyword">virtual</span> <span class="keywordtype">void</span> setMaterialFlag(video::E_MATERIAL_FLAG flag, <span class="keywordtype">bool</span> newvalue)</div><div class="line">    {</div><div class="line">        Material.setFlag(flag, newvalue);</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="keywordtype">void</span> setMaterialTexture(u32 textureLayer, video::ITexture* texture)</div><div class="line">    {</div><div class="line">        Material.setTexture(textureLayer, texture);</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="keyword">virtual</span> <span class="keywordtype">void</span> setMaterialType(video::E_MATERIAL_TYPE newType)</div><div class="line">    {</div><div class="line">        Material.MaterialType = newType;</div><div class="line">    }</div><div class="line"></div><div class="line"><span class="keyword">private</span>:</div><div class="line"></div><div class="line">    video::IVideoDriver *Driver;</div><div class="line">    video::S3DVertex Vertices[4];</div><div class="line">    u16 Indices[6];</div><div class="line">    video::SMaterial Material;</div><div class="line">};</div></div><!-- fragment --><p> We start up the engine just like before. Then shader programs are selected according to the driver type. </p><div class="fragment"><div class="line"><span class="keywordtype">int</span> main()</div><div class="line">{</div><div class="line">    <span class="comment">// ask user for driver</span></div><div class="line">    video::E_DRIVER_TYPE driverType=driverChoiceConsole();</div><div class="line">    <span class="keywordflow">if</span> (driverType==video::EDT_COUNT)</div><div class="line">        <span class="keywordflow">return</span> 1;</div><div class="line"></div><div class="line">    <span class="comment">// create device</span></div><div class="line">    device = createDevice(driverType, core::dimension2d&lt;u32&gt;(640, 480));</div><div class="line"></div><div class="line">    <span class="keywordflow">if</span> (device == 0)</div><div class="line">        <span class="keywordflow">return</span> 1; <span class="comment">// could not create selected driver.</span></div><div class="line"></div><div class="line">    video::IVideoDriver* driver = device-&gt;getVideoDriver();</div><div class="line">    scene::ISceneManager* smgr = device-&gt;getSceneManager();</div></div><!-- fragment --><p> In this example, high level post processing shaders are loaded for both Direct3D and OpenGL drivers. File pp_d3d9.hlsl is for Direct3D 9, and pp_opengl.frag/pp_opengl.vert are for OpenGL. </p><div class="fragment"><div class="line"><span class="keyword">const</span> io::path mediaPath = getExampleMediaPath();</div><div class="line">io::path vsFileName; <span class="comment">// filename for the vertex shader</span></div><div class="line">io::path psFileName; <span class="comment">// filename for the pixel shader</span></div><div class="line"></div><div class="line"><span class="keywordflow">switch</span>(driverType)</div><div class="line">{</div><div class="line"><span class="keywordflow">case</span> video::EDT_DIRECT3D9:</div><div class="line">    psFileName = mediaPath + <span class="stringliteral">&quot;pp_d3d9.hlsl&quot;</span>;</div><div class="line">    vsFileName = psFileName; <span class="comment">// both shaders are in the same file</span></div><div class="line">    <span class="keywordflow">break</span>;</div><div class="line"></div><div class="line"><span class="keywordflow">case</span> video::EDT_OPENGL:</div><div class="line">    psFileName = mediaPath + <span class="stringliteral">&quot;pp_opengl.frag&quot;</span>;</div><div class="line">    vsFileName = mediaPath + <span class="stringliteral">&quot;pp_opengl.vert&quot;</span>;</div><div class="line">    <span class="keywordflow">break</span>;</div><div class="line">}</div></div><!-- fragment --><p> Check for hardware capability of executing the corresponding shaders on selected renderer. This is not necessary though. </p><div class="fragment"><div class="line"><span class="keywordflow">if</span> (!driver-&gt;queryFeature(video::EVDF_PIXEL_SHADER_1_1) &amp;&amp;</div><div class="line">    !driver-&gt;queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1))</div><div class="line">{</div><div class="line">    device-&gt;getLogger()-&gt;log(<span class="stringliteral">&quot;WARNING: Pixel shaders disabled &quot;</span>\</div><div class="line">        <span class="stringliteral">&quot;because of missing driver/hardware support.&quot;</span>);</div><div class="line">    psFileName = <span class="stringliteral">&quot;&quot;</span>;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (!driver-&gt;queryFeature(video::EVDF_VERTEX_SHADER_1_1) &amp;&amp;</div><div class="line">    !driver-&gt;queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1))</div><div class="line">{</div><div class="line">    device-&gt;getLogger()-&gt;log(<span class="stringliteral">&quot;WARNING: Vertex shaders disabled &quot;</span>\</div><div class="line">        <span class="stringliteral">&quot;because of missing driver/hardware support.&quot;</span>);</div><div class="line">    vsFileName = <span class="stringliteral">&quot;&quot;</span>;</div><div class="line">}</div></div><!-- fragment --><p> An animated mesh is loaded to be displayed. As in most examples, we'll take the fairy md2 model. </p><div class="fragment"><div class="line"><span class="comment">// load and display animated fairy mesh</span></div><div class="line"></div><div class="line">scene::IAnimatedMeshSceneNode* fairy = smgr-&gt;addAnimatedMeshSceneNode(</div><div class="line">    smgr-&gt;getMesh(mediaPath + <span class="stringliteral">&quot;faerie.md2&quot;</span>));</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (fairy)</div><div class="line">{</div><div class="line">    fairy-&gt;setMaterialTexture(0,</div><div class="line">            driver-&gt;getTexture(mediaPath + <span class="stringliteral">&quot;faerie2.bmp&quot;</span>)); <span class="comment">// set diffuse texture</span></div><div class="line">    fairy-&gt;setMaterialFlag(video::EMF_LIGHTING, <span class="keyword">false</span>); <span class="comment">// disable dynamic lighting</span></div><div class="line">    fairy-&gt;setPosition(core::vector3df(-10,0,-100));</div><div class="line">    fairy-&gt;setMD2Animation ( scene::EMAT_STAND );</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// add scene camera</span></div><div class="line">smgr-&gt;addCameraSceneNode(0, core::vector3df(10,10,-80),</div><div class="line">    core::vector3df(-10,10,-100));</div></div><!-- fragment --><p> We create a render target texture (RTT) with the same size as frame buffer. Instead of rendering the scene directly to the frame buffer, we firstly render it to this RTT. Post processing is then applied based on this RTT. RTT size needs not to be the same with frame buffer though. However in this example, we expect the result of rendering to RTT to be consistent with the result of rendering directly to the frame buffer. Therefore, the size of RTT keeps the same with frame buffer. </p><div class="fragment"><div class="line"><span class="comment">// create render target</span></div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (driver-&gt;queryFeature(video::EVDF_RENDER_TO_TARGET))</div><div class="line">{</div><div class="line">    rt = driver-&gt;addRenderTargetTexture(core::dimension2d&lt;u32&gt;(640, 480), <span class="stringliteral">&quot;RTT1&quot;</span>);</div><div class="line">}</div><div class="line"><span class="keywordflow">else</span></div><div class="line">{</div><div class="line">    device-&gt;getLogger()-&gt;log(<span class="stringliteral">&quot;Your hardware or this renderer is not able to use the &quot;</span>\</div><div class="line">        <span class="stringliteral">&quot;render to texture feature. RTT Disabled.&quot;</span>);</div><div class="line">}</div></div><!-- fragment --><p> Post processing is achieved by rendering a screen quad with this RTT (with previously rendered result) as a texture on the quad. A screen quad is geometry of flat plane composed of two adjacent triangles covering the entire area of viewport. In this pass of rendering, RTT works just like a normal texture and is drawn on the quad during rendering. We can then take control of this rendering process by applying various shader-defined materials to the quad. In other words, we can achieve different effect by writing different shaders. This process is called post processing because it normally does not rely on scene geometry. The inputs of this process are just textures, or in other words, just images. With the help of screen quad, we can draw these images on the screen with different effects. For example, we can adjust contrast, make grayscale, add noise, do more fancy effect such as blur, bloom, ghost, or just like in this example, we invert the color to produce negative image. Note that post processing is not limited to use only one texture. It can take multiple textures as shader inputs to provide desired result. In addition, post processing can also be chained to produce compound result. </p><div class="fragment"><div class="line"><span class="comment">// we create a screen quad</span></div><div class="line">ScreenQuad *screenQuad = <span class="keyword">new</span> ScreenQuad(driver);</div><div class="line"></div><div class="line"><span class="comment">// turn off mip maps and bilinear filter since we do not want interpolated result</span></div><div class="line">screenQuad-&gt;setMaterialFlag(video::EMF_USE_MIP_MAPS, <span class="keyword">false</span>);</div><div class="line">screenQuad-&gt;setMaterialFlag(video::EMF_BILINEAR_FILTER, <span class="keyword">false</span>);</div><div class="line"></div><div class="line"><span class="comment">// set quad texture to RTT we just create</span></div><div class="line">screenQuad-&gt;setMaterialTexture(0, rt);</div></div><!-- fragment --><p> Let's create material for the quad. Like in other example, we create material using IGPUProgrammingServices and call addShaderMaterialFromFiles, which returns a material type identifier. </p><div class="fragment"><div class="line"><span class="comment">// create materials</span></div><div class="line"></div><div class="line">video::IGPUProgrammingServices* gpu = driver-&gt;getGPUProgrammingServices();</div><div class="line">s32 ppMaterialType = 0;</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (gpu)</div><div class="line">{</div><div class="line">    <span class="comment">// We write a QuadShaderCallBack class that implements OnSetConstants </span></div><div class="line">    <span class="comment">// callback of IShaderConstantSetCallBack class at the beginning of </span></div><div class="line">    <span class="comment">// this tutorial. We set shader constants in this callback.</span></div><div class="line"></div><div class="line">    <span class="comment">// create an instance of callback class</span></div><div class="line"></div><div class="line">    QuadShaderCallBack* mc = <span class="keyword">new</span> QuadShaderCallBack();</div><div class="line"></div><div class="line">    <span class="comment">// create material from post processing shaders</span></div><div class="line"></div><div class="line">    ppMaterialType = gpu-&gt;addHighLevelShaderMaterialFromFiles(</div><div class="line">        vsFileName, <span class="stringliteral">&quot;vertexMain&quot;</span>, video::EVST_VS_1_1,</div><div class="line">        psFileName, <span class="stringliteral">&quot;pixelMain&quot;</span>, video::EPST_PS_1_1, mc);</div><div class="line"></div><div class="line">    mc-&gt;drop();</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// set post processing material type to the quad</span></div><div class="line">screenQuad-&gt;setMaterialType((video::E_MATERIAL_TYPE)ppMaterialType);</div></div><!-- fragment --><p> Now draw everything. That's all. </p><div class="fragment"><div class="line">    <span class="keywordtype">int</span> lastFPS = -1;</div><div class="line"></div><div class="line">    <span class="keywordflow">while</span>(device-&gt;run())</div><div class="line">    {</div><div class="line">        <span class="keywordflow">if</span> (device-&gt;isWindowActive())</div><div class="line">        {</div><div class="line">            driver-&gt;beginScene(<span class="keyword">true</span>, <span class="keyword">true</span>, video::SColor(255,0,0,0));</div><div class="line"></div><div class="line">            <span class="keywordflow">if</span> (rt)</div><div class="line">            {</div><div class="line">                <span class="comment">// draw scene into render target</span></div><div class="line"></div><div class="line">                <span class="comment">// set render target to RTT</span></div><div class="line">                driver-&gt;setRenderTarget(rt, <span class="keyword">true</span>, <span class="keyword">true</span>, video::SColor(255,0,0,0));</div><div class="line"></div><div class="line">                <span class="comment">// draw scene to RTT just like normal rendering</span></div><div class="line">                smgr-&gt;drawAll();</div><div class="line"></div><div class="line">                <span class="comment">// after rendering to RTT, we change render target back</span></div><div class="line">                driver-&gt;setRenderTarget(0, <span class="keyword">true</span>, <span class="keyword">true</span>, video::SColor(255,0,0,0));</div><div class="line"></div><div class="line">                <span class="comment">// render screen quad to apply post processing</span></div><div class="line">                screenQuad-&gt;render();</div><div class="line">            }</div><div class="line">            <span class="keywordflow">else</span></div><div class="line">            {</div><div class="line">                <span class="comment">// draw scene normally</span></div><div class="line">                smgr-&gt;drawAll();</div><div class="line">            }</div><div class="line"></div><div class="line">            driver-&gt;endScene();</div><div class="line"></div><div class="line">            <span class="keywordtype">int</span> fps = driver-&gt;getFPS();</div><div class="line"></div><div class="line">            <span class="keywordflow">if</span> (lastFPS != fps)</div><div class="line">            {</div><div class="line">                core::stringw str = L<span class="stringliteral">&quot;Irrlicht Engine - Post processing example [&quot;</span>;</div><div class="line">                str += driver-&gt;getName();</div><div class="line">                str += <span class="stringliteral">&quot;] FPS:&quot;</span>;</div><div class="line">                str += fps;</div><div class="line"></div><div class="line">                device-&gt;setWindowCaption(str.c_str());</div><div class="line">                lastFPS = fps;</div><div class="line">            }</div><div class="line">        }</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="comment">// do not forget to manually drop the screen quad</span></div><div class="line"></div><div class="line">    screenQuad-&gt;drop();</div><div class="line"></div><div class="line">    device-&gt;drop();</div><div class="line"></div><div class="line">    <span class="keywordflow">return</span> 0;</div><div class="line">}</div></div><!-- fragment --> </div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.13-->
<!-- start footer part -->
<p>&nbsp;</p>
</body>
</html>
